package com.mobile2you.nci.android.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class LoadImagePool {

	private static int IMAGE_POOL_SIZE = 20;

	private static int THREAD_POOL_SIZE = 3;

	@SuppressWarnings("unused")
	private static String[] urls = new String[IMAGE_POOL_SIZE];
	private static LoaderThread[] threads = new LoaderThread[THREAD_POOL_SIZE];
	private static ArrayList<Request> queue = new ArrayList<Request>(40);

	/** Index of next image add in cache */
	@SuppressWarnings("unused")
	private static int nextIndex;
	private static Context context;
	private static boolean high;

	static Handler downloadFinishedHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			int poolIndex = msg.what;
			if (!queue.isEmpty()) {
				// Reuse slot to start a new thread
				LoaderThread thread = new LoaderThread(context, queue.get(queue
						.size() - 1), poolIndex, high);
				queue.remove(queue.size() - 1);
				LoadImagePool.threads[poolIndex] = thread;
				thread.start();
			} else {
				// Free slot
				LoadImagePool.threads[poolIndex] = null;
			}
		}
	};

	/** A thread to execute a download request */
	private static class LoaderThread extends Thread {
		public String url;
		private final Handler h;
		private final int poolIndex;
		public boolean killed;

		private final Context context;

		boolean high;

		FileCache fileCache;

		public LoaderThread(Context context, Request r, int poolIndex,
				boolean high) {
			url = r.url;
			h = r.h;
			this.poolIndex = poolIndex;
			setPriority(Thread.MAX_PRIORITY);
			this.context = context;
			this.high = high;
			fileCache = new FileCache(context);
		}

		public LoaderThread(Context context, String url, Handler h,
				int poolIndex, boolean high) {
			this.url = url;
			this.h = h;
			this.poolIndex = poolIndex;
			this.context = context;
			this.high = high;
			setPriority(Thread.MAX_PRIORITY);
			fileCache = new FileCache(context);

		}

		@Override
		public void run() {
			Looper.prepare();
			try {
				Bitmap image = null;
				if (!high) {
					image = ImageUtils.getInstance(context).getBitmapMin(url);
				} else {
					image = ImageUtils.getInstance(context).getBitmapHigh(url);
				}
				Bitmap bitmap = null;
				if (image != null) {
					bitmap = image;
				} else {
					File f = fileCache.getFile(url);
					URL imageUrl = new URL(url);
					HttpURLConnection conn = (HttpURLConnection) imageUrl
							.openConnection();
					conn.setConnectTimeout(30000);
					conn.setReadTimeout(30000);
					InputStream is = conn.getInputStream();
					OutputStream os = new FileOutputStream(f);
					ImageUtils.copyStream(is, os);
					os.close();
					if (!high) {
						bitmap = ImageUtils.getInstance(context).getBitmapMin(
								url);
					} else {
						bitmap = ImageUtils.getInstance(context).getBitmapHigh(
								url);
					}

				}
				// Load image from url

				if (!killed) {
					Message finishedMessage = Message.obtain(h);
					finishedMessage.obj = bitmap;
					finishedMessage.sendToTarget();
					stopDownload(url);
				}
			} catch (Exception e) {

				Message failureMessage = Message.obtain(h);
				failureMessage.obj = null;
				failureMessage.sendToTarget();
			}

			// Notify pool that thread has finished loading
			LoadImagePool.downloadFinishedHandler.sendEmptyMessage(poolIndex);
			Looper.myLooper().quit();
		}
	}

	/** A download request */
	private static class Request {
		public String url;
		public Handler h;

		public Request(String url, Handler h) {
			this.url = url;
			this.h = h;
		}
	}

	/**
	 * Add a downloading query in queue. The download will start as soon as a
	 * thread is available
	 * 
	 * @param url
	 *            The url of the image to download
	 * @param h
	 *            The handler that will receive image when downloaded
	 */
	public static synchronized void loadImage(Context context, String url,
			Handler h, boolean high) {
		LoadImagePool.context = context;
		LoadImagePool.high = high;
		// Search for an available thread slot
		for (int i = 0; i < THREAD_POOL_SIZE; i++) {
			if (threads[i] == null) {
				// Free slot, start a thread immediatly
				LoaderThread thread = new LoaderThread(context, url, h, i, high);
				threads[i] = thread;
				thread.start();
			}
		}
		// No thread slot available, add request in queue
		queue.add(new Request(url, h));
	}

	/** Stop all current downloads and clear query queue. */
	public static synchronized void stopDownload() {
		// Free queue
		queue.clear();
		// Stop all active threads (do not send imaged loaded callback message)
		for (int i = 0; i < THREAD_POOL_SIZE; i++) {
			threads[i].killed = true;
		}
	}

	/**
	 * Stop refreshing image (reuse view)
	 * 
	 * @param url
	 *            The url to stop
	 */
	public static synchronized void stopDownload(String url) {
		for (int i = 0; i < THREAD_POOL_SIZE; i++) {
			if (threads[i] != null && threads[i].url.equals(url)) {
				threads[i].killed = true;
				return;
			}
		}
	}

}
